package tech.xs.sdk.minio;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import tech.xs.sdk.minio.domain.enums.MinioReadWriteAuthEnums;
import tech.xs.sdk.minio.domain.exception.MinioException;
import tech.xs.sdk.minio.domain.properties.MinioProperties;

import java.io.InputStream;

@Slf4j
public class MinioSdk {

    public static final String BUCKET_AUTH_PUBLIC_READ;

    static {
        JSONObject bucketAuth = new JSONObject();
        bucketAuth.put("Version", "2012-10-17");
        JSONArray statement = new JSONArray();
        JSONObject bucketAuthPublicRead = new JSONObject();
        bucketAuthPublicRead.put("Sid", "AddPerm");
        bucketAuthPublicRead.put("Effect", "Allow");

        JSONObject bucketAuthPublicReadPrincipal = new JSONObject();
        bucketAuthPublicReadPrincipal.put("AWS", "*");
        bucketAuthPublicRead.put("Principal", bucketAuthPublicReadPrincipal);

        JSONArray bucketAuthPublicReadAction = new JSONArray();
        bucketAuthPublicReadAction.add("s3:GetObject");
        bucketAuthPublicRead.put("Action", bucketAuthPublicReadAction);

        JSONArray bucketAuthPublicResource = new JSONArray();
        bucketAuthPublicRead.put("Resource", bucketAuthPublicResource);

        statement.add(bucketAuthPublicRead);
        bucketAuth.put("Statement", statement);
        BUCKET_AUTH_PUBLIC_READ = bucketAuth.toJSONString();
    }

    private final MinioProperties properties;

    public MinioSdk(MinioProperties properties) {
        this.properties = properties;
    }

    public boolean isExistBucket(String bucketName) throws MinioException {
        try {
            MinioClient client = getMinioClient();
            return client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public void createBucket(String bucketName) {
        try {
            log.info("minio 创建存储桶 bucketName:" + bucketName);
            MinioClient client = getMinioClient();
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public void createBucket(String bucketName, MinioReadWriteAuthEnums bucketAuth) {
        try {
            log.info("minio 创建存储桶 bucketName:" + bucketName + " bucketAuth:" + bucketAuth);
            MinioClient client = getMinioClient();
            client.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
            setBucketAuth(bucketName, bucketAuth);
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public void setBucketAuth(String bucketName, MinioReadWriteAuthEnums bucketAuth) {
        try {
            MinioClient client = getMinioClient();
            String authStr = null;
            if (MinioReadWriteAuthEnums.publicRead.equals(bucketAuth)) {
                JSONObject auth = JSONObject.parseObject(BUCKET_AUTH_PUBLIC_READ);
                JSONArray resources = auth.getJSONArray("Statement").getJSONObject(0).getJSONArray("Resource");
                resources.add("arn:aws:s3:::" + bucketName + "/*");
                authStr = auth.toJSONString();
            } else {
                throw new MinioException("不存在对应权限");
            }

            log.info("minio 设置存储桶权限:" + authStr);
            client.setBucketPolicy(SetBucketPolicyArgs.builder()
                    .bucket(bucketName)
                    .config(authStr)
                    .build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public InputStream download(String bucketName, String path) {
        try {
            log.info("minio 下载文件 bucketName:" + bucketName + " path:" + path);
            MinioClient client = getMinioClient();
            return client.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path)
                    .build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public void upload(String bucketName, String path, InputStream stream) {
        try (stream) {
            log.info("minio 上传文件 bucketName:" + bucketName + " path:" + path);
            MinioClient client = getMinioClient();
            client.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path)
                    .stream(stream, -1, 10485760)
                    .build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    public void delete(String bucketName, String path) {
        try {
            log.info("minio 删除文件 bucketName:" + bucketName + " path:" + path);
            MinioClient client = getMinioClient();
            client.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(path).build());
        } catch (Exception e) {
            throw new MinioException(e.getMessage(), e);
        }
    }

    private MinioClient getMinioClient() {
        return MinioClient.builder()
                .endpoint(properties.getEndpoint())
                .credentials(properties.getAccessKey(), properties.getSecretKey())
                .build();
    }

}
